<?php

namespace App\Exceptions;

use Throwable;
use App\Traits\ApiResponse;
use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse;
use App\Exceptions\Api\V1\ApiException;
use App\Exceptions\Pro\V1\ProException;
use Tymon\JWTAuth\Exceptions\JWTException;
use App\Exceptions\Admin\V1\AdminException;
use Illuminate\Auth\AuthenticationException;
use App\Exceptions\Admin\V1\GeneralException;
use Illuminate\Validation\ValidationException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;

class Handler extends ExceptionHandler
{
    use ApiResponse;

    /**
     * @var array
     */
    protected $dontReport = [
        //
    ];

    /**
     * @var string[]
     */
    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    /**
     * @param Throwable $exception
     * @throws Throwable
     * @author 陈文小超
     * @maxim from专注to执行
     * @time 2021/3/18/17:11
     */
    public function report(Throwable $exception)
    {
        parent::report($exception);
    }

    /**
     * @param \Illuminate\Http\Request $request
     * @param Throwable $exception
     * @return JsonResponse|Response|\Symfony\Component\HttpFoundation\Response
     * @throws Throwable
     * @author 陈文小超
     * @maxim from专注to执行
     * @time 2021/3/18/17:12
     */
    public function render($request, Throwable $exception)
    {
        $errorCode = GeneralException::ADMIN_LOGIN_RETRIEVE_INVALID;
        $errorMsg = trans('');
        $errorHeaders = [];
        if ($exception instanceof GeneralException || $exception instanceof AdminException
            || $exception instanceof ProException || $exception instanceof ApiException) {
            $errorCode = $exception->errorCode;
            $errorMsg = $exception->errorMsg;
            $errorHeaders = $exception->errorHeaders;
        } elseif ($exception instanceof UnauthorizedHttpException) {
            $errorCode = GeneralException::ADMIN_LOGIN_RETRIEVE_INVALID;
            $errorMsg = trans('exception\v1\general.' . $errorCode);
        } elseif ($exception instanceof TokenExpiredException
            || $exception instanceof TokenInvalidException
            || $exception instanceof TokenBlacklistedException) {
            $errorCode = GeneralException::ADMIN_LOGIN_RETRIEVE_INVALID;
            $errorMsg = trans('exception\v1\general.' . $errorCode);
        } elseif ($exception instanceof JWTException) {
            $errorCode = GeneralException::ADMIN_LOGIN_RETRIEVE_INVALID;
            $errorMsg = trans('exception\v1\general.' . $errorCode);
        } elseif ($exception instanceof NotFoundHttpException || $exception instanceof MethodNotAllowedHttpException) {
            $errorCode = GeneralException::ADMIN_LOGIN_RETRIEVE_INVALID;
            $errorMsg = trans('exception\v1\general.' . $errorCode);
        } elseif ($exception instanceof ValidationException) {
            $errorCode = GeneralException::ADMIN_LOGIN_RETRIEVE_INVALID;
            $errorMsgArr = $exception->errors();
            $currentErrorMsg = current($errorMsgArr);
            $errorMsg = (is_array($currentErrorMsg) && !empty($currentErrorMsg)) ? reset($currentErrorMsg) :
                trans('exception\v1\general.' . $errorCode);
        } elseif ($exception instanceof AuthenticationException) {
            $errorCode = GeneralException::ADMIN_LOGIN_RETRIEVE_INVALID;
            $errorMsg = trans('exception\v1\general.' . $errorCode);
        }
        if ($request->expectsJson()) {
            $extra = [];
            if (config('app.debug')) {
                $extra['exception'] = [
                    'class'   => get_class($exception),
                    'code'    => $exception->getCode(),
                    'message' => $exception->getMessage(),
                    'file'    => $exception->getFile(),
                    'line'    => $exception->getLine(),
                ];
            }

            return $this->failed($errorCode, $errorMsg, $extra, $errorHeaders);
        }

        return parent::render($request, $exception);
    }
}
